home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / adt / selfuncs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.8 KB  |  468 lines

  1. /*
  2.  * selfuncs.c --
  3.  *    Selectivity functions for system catalogs and builtin types
  4.  *
  5.  *    These routines are registered in the operator catalog in the
  6.  *    "oprrest" and "oprjoin" attributes.
  7.  *
  8.  *    XXX check all the functions--I suspect them to be 1-based.
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <strings.h>
  13.  
  14. #include "access/heapam.h"
  15. #include "access/tqual.h"    /* for NowTimeQual */
  16. #include "utils/fmgr.h"
  17. #include "utils/builtins.h"    /* for textout() prototype */
  18. #include "utils/log.h"
  19.  
  20. #include "catalog/catname.h"
  21. #include "catalog/syscache.h"
  22. #include "catalog/pg_statistic.h"
  23.  
  24. RcsId("$Header: /private/postgres/src/utils/adt/RCS/selfuncs.c,v 1.19 1992/01/13 02:21:26 mao Exp $");
  25.  
  26. /* N is not a valid var/constant or relation id */
  27. #define    NONVALUE(N)    ((N) == -1)
  28.  
  29. /* 
  30.  * generalize the test for functional index selectivity request
  31.  */
  32. #define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttributeNumber)
  33.  
  34. int32 getattnvals ARGS((ObjectId relid , AttributeNumber attnum ));
  35. int gethilokey ARGS((ObjectId relid , AttributeNumber attnum , ObjectId opid , char **high , char **low ));
  36.  
  37.  
  38. /*
  39.  *    eqsel        - Selectivity of "=" for any data type.
  40.  */
  41. /*ARGSUSED*/
  42. float64
  43. eqsel(opid, relid, attno, value, flag)
  44.     ObjectId    opid;
  45.     ObjectId    relid;
  46.     AttributeNumber    attno;
  47.     char        *value;
  48.     int32        flag;
  49. {
  50.     int32        nvals;
  51.     float64        result;
  52.  
  53.     result = (float64) palloc(sizeof(float64data));
  54.     if (NONVALUE(attno) || NONVALUE(relid))
  55.         *result = 0.1;
  56.     else {
  57.         nvals = getattnvals(relid, (int) attno);
  58.         if (nvals == 0)
  59.             *result = 0.0;
  60.         else
  61.             *result = 1.0 / nvals;
  62.     }
  63.     return(result);
  64. }
  65.  
  66. /*
  67.  *    neqsel        - Selectivity of "!=" for any data type.
  68.  */
  69. float64
  70. neqsel(opid, relid, attno, value, flag)
  71.     ObjectId    opid;
  72.     ObjectId    relid;
  73.     AttributeNumber    attno;
  74.     char        *value;
  75.     int32        flag;
  76. {
  77.     float64        result;
  78.  
  79.     result = eqsel(opid, relid, attno, value, flag);
  80.     *result = 1.0 - *result;
  81.     return(result);
  82. }
  83.  
  84. /*
  85.  *    intltsel    - Selectivity of "<" for integers.
  86.  *              Should work for both longs and shorts.
  87.  */
  88. float64
  89. intltsel(opid, relid, attno, value, flag)
  90.     ObjectId    opid;
  91.     ObjectId    relid;
  92.     AttributeNumber    attno;
  93. /* XXX    char        *value;*/
  94.     int32        value;
  95.     int32        flag;
  96. {
  97.     float64     result;
  98.     char        *highchar, *lowchar;
  99.     long        val, high, low, top, bottom;
  100.     extern long    atol();
  101.  
  102.     result = (float64) palloc(sizeof(float64data));
  103.     if (NONVALUE(attno) || NONVALUE(relid))
  104.         *result = 1.0 / 3;
  105.     else {
  106. /* XXX          val = atol(value);*/
  107.                 val = value;
  108.                 gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
  109.                 if (*highchar == 'n' || *lowchar == 'n') {
  110.                         *result = 1.0/3.0;
  111.                         return (result);
  112.                 }
  113.                 high = atol(highchar);
  114.                 low = atol(lowchar);
  115.                 if ((flag & SEL_RIGHT && val < low) ||
  116.                     (!(flag & SEL_RIGHT) && val > high)) {
  117.                    int nvals;
  118.                    nvals = getattnvals(relid, (int) attno);
  119.                    if (nvals == 0)
  120.                         *result = 1.0 / 3.0;
  121.                    else
  122.                         *result = 3.0 / nvals;
  123.               }
  124.                 else {
  125.                         bottom = high - low;
  126.                         if (bottom == 0)
  127.                                 ++bottom;
  128.                         if (flag & SEL_RIGHT)
  129.                                 top = val - low;
  130.                         else
  131.                                 top = high - val;
  132.                         if (top > bottom)
  133.                                 *result = 1.0;
  134.                         else {
  135.                                 if (top == 0)
  136.                                    ++top;
  137.                                 *result = ((1.0 * top) / bottom);
  138.                         }
  139.                 }
  140.     }
  141.     return(result);
  142. }
  143.  
  144. /*
  145.  *    intgtsel    - Selectivity of ">" for integers.
  146.  *              Should work for both longs and shorts.
  147.  */
  148. float64
  149. intgtsel(opid, relid, attno, value, flag)
  150.     ObjectId    opid;
  151.     ObjectId    relid;
  152.     AttributeNumber    attno;
  153. /* XXX    char        *value;*/
  154.     int32        value;
  155.     int32        flag;
  156. {
  157.     float64        result;
  158.     int        notflag;
  159.  
  160.     if (flag & 0)
  161.         notflag = flag & ~SEL_RIGHT;
  162.     else
  163.         notflag = flag | SEL_RIGHT;
  164.     result = intltsel(opid, relid, attno, value, (int32) notflag);
  165.     return(result);
  166. }
  167.  
  168. /*
  169.  *    eqjoinsel    - Join selectivity of "="
  170.  */
  171. /*ARGSUSED*/
  172. float64
  173. eqjoinsel(opid, relid1, attno1, relid2, attno2)
  174.     ObjectId    opid;
  175.     ObjectId    relid1;
  176.     AttributeNumber    attno1;
  177.     ObjectId    relid2;
  178.     AttributeNumber    attno2;
  179. {
  180.     float64        result;
  181.     int32        num1, num2, max;
  182.  
  183.     result = (float64) palloc(sizeof(float64data));
  184.     if (NONVALUE(attno1) || NONVALUE(relid1) ||
  185.         NONVALUE(attno2) || NONVALUE(relid2))
  186.         *result = 0.1;
  187.     else {
  188.         num1 = getattnvals(relid1, (int) attno1);
  189.         num2 = getattnvals(relid2, (int) attno2);
  190.         max = (num1 > num2) ? num1 : num2;
  191.         if (max == 0)
  192.             *result = 1.0;
  193.         else
  194.             *result = 1.0 / max;
  195.     }
  196.     return(result);
  197. }
  198.  
  199. /*
  200.  *    neqjoinsel    - Join selectivity of "!="
  201.  */
  202. float64
  203. neqjoinsel(opid, relid1, attno1, relid2, attno2)
  204.     ObjectId    opid;
  205.     ObjectId    relid1;
  206.     AttributeNumber    attno1;
  207.     ObjectId    relid2;
  208.     AttributeNumber    attno2;
  209. {
  210.     float64        result;
  211.  
  212.     result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
  213.     *result = 1.0 - *result;
  214.     return(result);
  215. }
  216.  
  217. /*
  218.  *    intltjoinsel    - Join selectivity of "<"
  219.  */
  220. /*ARGSUSED*/
  221. float64
  222. intltjoinsel(opid, relid1, attno1, relid2, attno2)
  223.     ObjectId    opid;
  224.     ObjectId    relid1;
  225.     AttributeNumber    attno1;
  226.     ObjectId    relid2;
  227.     AttributeNumber    attno2;
  228. {
  229.     float64    result;
  230.  
  231.     result = (float64) palloc(sizeof(float64data));
  232.     *result = 1.0 / 3.0;
  233.     return(result);
  234. }
  235.  
  236. /*
  237.  *    intgtjoinsel    - Join selectivity of ">"
  238.  */
  239. /*ARGSUSED*/
  240. float64
  241. intgtjoinsel(opid, relid1, attno1, relid2, attno2)
  242.     ObjectId    opid;
  243.     ObjectId    relid1;
  244.     AttributeNumber    attno1;
  245.     ObjectId    relid2;
  246.     AttributeNumber    attno2;
  247. {
  248.     float64    result;
  249.  
  250.     result = (float64) palloc(sizeof(float64data));
  251.     *result = 1.0 / 3.0;
  252.     return(result);
  253. }
  254.  
  255. /*
  256.  *    getattnvals    - Retrieves the number of values within an attribute.
  257.  *
  258.  *    Note:
  259.  *        getattnvals and gethilokey both currently use keyed
  260.  *        relation scans and amgetattr.  Alternatively,
  261.  *        the relation scan could be non-keyed and the tuple
  262.  *        returned could be cast (struct X *) tuple + tuple->t_hoff.
  263.  *        The first method is good for testing the implementation,
  264.  *        but the second may ultimately be faster?!?  In any case,
  265.  *        using the cast instead of amgetattr would be
  266.  *        more efficient.  However, the cast will not work
  267.  *        for gethilokey which accesses stahikey in struct statistic.
  268.  */
  269. int32
  270. getattnvals(relid, attnum)
  271.     ObjectId    relid;
  272.     AttributeNumber    attnum;
  273. {
  274.     HeapTuple    atp;
  275.     int        nvals;
  276.  
  277.         atp = SearchSysCacheTuple(ATTNUM, relid, attnum, NULL, NULL);
  278.         if (!HeapTupleIsValid(atp)) {
  279.                 elog(WARN, "getattnvals: no attribute tuple %d %d",
  280.                      relid, attnum);
  281.                 return(0);
  282.         }
  283.         nvals = ((struct attribute *) GETSTRUCT(atp))->attnvals;
  284.     if (nvals > 0) return(nvals);
  285.  
  286.     atp = SearchSysCacheTuple(RELOID, relid, NULL, NULL, NULL);
  287.     /* XXX -- use number of tuples as number of distinctive values
  288.        just for now, in case number of distinctive values is
  289.        not cached */
  290.     if (!HeapTupleIsValid(atp)) {
  291.         elog(WARN, "getattnvals: no relation tuple %d", relid);
  292.         return(0);
  293.     }
  294.     nvals = ((RelationTupleForm) GETSTRUCT(atp))->reltuples;
  295.     return(nvals);
  296. }
  297.  
  298. /*
  299.  *    gethilokey    - Returns a pointer to strings containing
  300.  *              the high and low keys within an attribute.
  301.  *
  302.  *    Currently returns "0", and "0" in high and low if the statistic
  303.  *    catalog does not contain the proper tuple.  Eventually, the
  304.  *    statistic demon should have the tuple maintained, and it should
  305.  *    elog() if the tuple is missing.
  306.  *
  307.  *    XXX Question: is this worth sticking in the catalog caches,
  308.  *        or will this get invalidated too often?
  309.  */
  310. gethilokey(relid, attnum, opid, high, low)
  311.     ObjectId    relid;
  312.     AttributeNumber    attnum;
  313.     ObjectId    opid;
  314.     char        **high;
  315.     char        **low;
  316. {
  317.     register Relation    rdesc;
  318.     register HeapScanDesc    sdesc;
  319.     static ScanKeyEntryData    key[3] = {
  320.         { 0, StatisticRelationIdAttributeNumber, F_OIDEQ },
  321.         { 0, StatisticAttributeNumberAttributeNumber, F_INT2EQ },
  322.         { 0, StatisticOperatorAttributeNumber, F_OIDEQ }
  323.     };
  324.     Boolean            isnull;
  325.     HeapTuple        tuple;
  326.  
  327.     rdesc = RelationNameOpenHeapRelation(StatisticRelationName);
  328.     key[0].argument = ObjectIdGetDatum(relid);
  329.     key[1].argument = Int16GetDatum((int16) attnum);
  330.     key[2].argument = ObjectIdGetDatum(opid);
  331.     sdesc = RelationBeginHeapScan(rdesc, 0, NowTimeQual,
  332.                       3, (ScanKey) key);
  333.     tuple = amgetnext(sdesc, 0, (Buffer *) NULL);
  334.     if (!HeapTupleIsValid(tuple)) {
  335.         *high = "n";
  336.         *low = "n";
  337. /* XXX         elog(WARN, "gethilokey: statistic tuple not found");*/
  338.         return;
  339.     }
  340.     *high = textout((struct varlena *)
  341.             amgetattr(tuple,
  342.                   InvalidBuffer,
  343.                   StatisticHighKeyAttributeNumber,
  344.                   &rdesc->rd_att,
  345.                   &isnull));
  346.     if (isnull)
  347.         elog(DEBUG, "gethilokey: high key is null");
  348.     *low = textout((struct varlena *)
  349.                amgetattr(tuple,
  350.                  InvalidBuffer,
  351.                  StatisticLowKeyAttributeNumber,
  352.                  &rdesc->rd_att,
  353.                  &isnull));
  354.     if (isnull)
  355.         elog(DEBUG, "gethilokey: low key is null");
  356.     HeapScanEnd(sdesc);
  357.     RelationCloseHeapRelation(rdesc);
  358. }
  359.  
  360. float64
  361. btreesel(operatorObjectId, indrelid, attributeNumber,
  362.      constValue, constFlag, nIndexKeys, indexrelid)
  363. ObjectId     operatorObjectId, indrelid, indexrelid;
  364. AttributeNumber attributeNumber;
  365. char        *constValue;
  366. int32        constFlag;
  367. int32        nIndexKeys;
  368. {
  369.     float64 result;
  370.     float64data resultData;
  371.  
  372.     if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
  373.         /*
  374.          * Need to call the functions selectivity
  375.          * function here.  For now simply assume it's
  376.          * 1/3 since functions don't currently
  377.          * have selectivity functions
  378.          */
  379.          resultData = 1.0 / 3.0;
  380.          result = &resultData;
  381.     }
  382.     else {
  383.         result = (float64)fmgr(get_oprrest (operatorObjectId),
  384.                     (char*)operatorObjectId,
  385.                     (char*)indrelid,
  386.                     (char*)attributeNumber,
  387.                     (char*)constValue,
  388.                     (char*)constFlag);
  389.     }
  390.  
  391.     if (!PointerIsValid(result))
  392.         elog(WARN, "Btree Selectivity: bad pointer");
  393.     if (*result < 0.0 || *result > 1.0)
  394.         elog(WARN, "Btree Selectivity: bad value %lf", *result);
  395.  
  396.     return(result);
  397. }
  398.  
  399. float64
  400. btreenpage(operatorObjectId, indrelid, attributeNumber,
  401.      constValue, constFlag, nIndexKeys, indexrelid)
  402. ObjectId     operatorObjectId, indrelid, indexrelid;
  403. AttributeNumber attributeNumber;
  404. char        *constValue;
  405. int32        constFlag;
  406. int32        nIndexKeys;
  407. {
  408.     float64 temp, result;
  409.     float64data tempData;
  410.     HeapTuple atp;
  411.     int npage;
  412.  
  413.     if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
  414.         /*
  415.          * Need to call the functions selectivity
  416.          * function here.  For now simply assume it's
  417.          * 1/3 since functions don't currently
  418.          * have selectivity functions
  419.          */
  420.          tempData = 1.0 / 3.0;
  421.          temp = &tempData;
  422.     }
  423.     else {
  424.         temp = (float64)fmgr(get_oprrest (operatorObjectId),
  425.                     (char*)operatorObjectId,
  426.                     (char*)indrelid,
  427.                     (char*)attributeNumber,
  428.                     (char*)constValue,
  429.                     (char*)constFlag);
  430.     }
  431.         atp = SearchSysCacheTuple(RELOID, indexrelid, NULL, NULL, NULL);
  432.         if (!HeapTupleIsValid(atp)) {
  433.                 elog(WARN, "btreenpage: no index tuple %d", indexrelid);
  434.                 return(0);
  435.         }
  436.     
  437.     npage = ((RelationTupleForm) GETSTRUCT(atp))->relpages;
  438.     result = (float64)palloc(sizeof(float64data));
  439.     *result = *temp * npage;
  440.     return(result);
  441. }
  442.  
  443. float64
  444. rtsel(operatorObjectId, indrelid, attributeNumber,
  445.       constValue, constFlag, nIndexKeys, indexrelid)
  446. ObjectId     operatorObjectId, indrelid, indexrelid;
  447. AttributeNumber attributeNumber;
  448. char        *constValue;
  449. int32        constFlag;
  450. int32        nIndexKeys;
  451. {
  452.     return (btreesel(operatorObjectId, indrelid, attributeNumber,
  453.              constValue, constFlag, nIndexKeys, indexrelid));
  454. }
  455.  
  456. float64
  457. rtnpage(operatorObjectId, indrelid, attributeNumber,
  458.      constValue, constFlag, nIndexKeys, indexrelid)
  459. ObjectId     operatorObjectId, indrelid, indexrelid;
  460. AttributeNumber attributeNumber;
  461. char        *constValue;
  462. int32        constFlag;
  463. int32        nIndexKeys;
  464. {
  465.     return (btreenpage(operatorObjectId, indrelid, attributeNumber,
  466.                constValue, constFlag, nIndexKeys, indexrelid));
  467. }
  468.